
#|____________________________________________________________________
 |
 |              RMDS.LSP - Multidimensional Scaling
 |
 |    Performs Classical or Replicated metric or nonmetric MDS
 |        Uses Kruskal's secondary monotone transformation 
 |            and the Guttman-deLeeuw SMACOF algorithm
 |              Copyright (c) 1997, Forrest W. Young, 
 |                Pedro Valero-Mora & Ruben Ledesma
 |
 |                  This is the main MDS Program.
 |      This program replaces the previous ViSta|MDS program.
 |           which is now called AMDS, for Averaged MDS
 |
 |                CONSTRUCTOR, CODE LOADING, ISNEW
 |
 | To maximize the chances of convergence to the global optimum, the
 | the algorithm uses what research shows is the best combination  
 | of routines. These include Torgerson-Young initialization, 
 | followed by Guttman-deLeeuw majorization with Kruskal's secondary 
 | monotonic transformation.
 |
 | Optimizes STRESS1, minimizing the sum-of-squared residuals of the
 | the fit of the euclidean distances to the montonically transformed data.
 | Converges on the local minimum only, but given the combination of
 | algorithms, it is known, by simulation, that it is likely to be 
 | the global minimum.
 |
 | Original Code by FWY April 1997
 | Modified Pedro Valero & Ruben Ledesma Feb 2001
 | Modified Forrest Young Oct 2001
 | Modified Forrest Young May 2002
 | Polished Forrest Young Sep 2002
 | Released Forrest Young Oct 2002
 |____________________________________________________________________
 |#

    
(defun multidimensional-scaling
  (&key (data *current-data*) 
        (dialog nil)
        (dimensions 3)            
        (monotone nil)            
        (iteration-plot t)                
        (iteration-report t)
        (niter 30)                
        (min-stress .001)
        (min-x-delta .001)        
        (min-stress-delta .0001))
"Args: (&key (data *current-data*) (dialog t) (dimensions 3) (monotone nil)  
             (iteration-plot nil) (iteration-report t) (niter 30) (min-stress .001)
             (min-x-delta .001) (min-stress-delta .0001))

Performs Metric or Nonmetric Multidimensional Scaling on one or more square and symmetric matrices of dissimilarities. The analysis is replicated when there is more than one matrix. 
Keyword arguments are 
  DATA, followed by the name of the data to be analyzed (default: *current-data*). If the data object contains 1 matrix of dissimilarities the analysis is a metric or nonmetric, non-replicated MDS. If more than one matrix, the analysis is metric or nonmetric replicated MDS. A dialog box is presented to get argument values if DIALOG is T.

  DIMENSIONS sets the dimensionality of the analysis (default 3, minimum 1)
  MONOTONE is nil (default) for metric MDS, t for nonmetric MDS
  ITERATION-REPORT - Present and update a report during iterations.
  ITERATION-PLOT   - Present and update a visualization during iterations.

Stops iterating when any one of the following stopping criteria are satisfied:
  NITER, the number of iterations (default 30);  
  MIN-STRESS (default .001) the minimum stress for stopping iterations; 
  MIN-STRESS-DELTA (default .0001) the minimum change in stress from one iteration to the next for stopping iterations; and 
  MIN-X-DELTA (default .001) the minimum of the maximum absolute value change in coordinates for stopping iterations. 

Places a list of results in results slot. Results list includes X, the NxR matrix of coordinates in Euclidean Space; D, the NxN matrix of Euclidean distances between those coordinates; T, the NxN matrix of transformed data (T= normalized DATA if monotone=nil); and Stress, the badness-of-fit.
Returns object identification.                          (constructor function)"

  (send rmds-model-proto :new 
        "Multidimensional Scaling"
        data dialog 
        dimensions monotone 
        iteration-plot iteration-report
        niter min-stress min-stress-delta min-x-delta)
  )
  
(load (strcat *mdscal-plugin-path* "nrmds5b0-object3.lsp"))
(load (strcat *mdscal-plugin-path* "nrmds5c04.lsp"))
(load (strcat *mdscal-plugin-path* "nrmds5d05.lsp"))
(load (strcat *mdscal-plugin-path* "nrmds5e06.lsp"))
(load (strcat *mdscal-plugin-path* "nrmds5f07.lsp"))

(defmeth rmds-model-proto :isnew 
  (title data dialog 
         dimensions monotone 
         iteration-plot iteration-report
         niter min-stress min-stress-delta min-x-delta)
  (if (not (equal data *current-data*))(setcd data))
  (cond
    ((not (equal (string-downcase (send data :datatype)) "matrix"))
     (fatal-message "Data must be Symmetric Matrix Data")
     (send *toolbox* :reset-button tool-name))
    (t
     (send self :nstim (send data :active-nvar '(numeric)))
     (when (< (send self :nstim) 4) 
           (fatal-message "Minimum number of active stimuli is 4"))
     (unless (equal (string-downcase (datashape? data)) "symmetric")
             (fatal-message "Data must be Symmetric Matrix Data"))
     (send self :nmats (send data :active-nmat '(symmetric)))
     (when (< (send self :nmats) 1) 
           (fatal-message "There must be at least one active data matrix."))
     (send self :datatype "matrix")
     (send self :dimensions dimensions)
     (when (> dimensions 9) (fatal-message "Maximum dimensionality is 9"))
     (send self :stimulus-names (send data :active-variables '(numeric)))
     (send self :monotone monotone)
     (send self :niter niter)
     (send self :iteration-report iteration-report)
     (send self :iteration-plot iteration-plot)
     (send self :min-stress min-stress)
     (send self :min-stress-delta min-stress-delta)
     (send self :min-x-delta min-x-delta)
     (send self :matrices (send data :matrices))
     (send self :data (send data :get-active-data-matrices))
     (call-next-method title data dialog)
     (when (send self :iteration-plot)
        (send self :visualize-model)
        (send *nrmds-iterplot-container* :close))
     )))
